﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Bonehead
{
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class ParsedCallstack
    {
        // tree members.
        private ParsedMethod mMethod;
        private Dictionary<ParsedMethod, ParsedCallstack> mChildren = new Dictionary<ParsedMethod, ParsedCallstack>();

        // statistics.
        private long mTransitionCount;
        private long mCycleCount;
        private long mMinCycleCount = long.MaxValue;
        private long mMaxCycleCount = long.MinValue;
        private long mCallCount;
        private long mExceptionCount;

        // methods.
        public ParsedCallstack(ParsedMethod aMethod)
        {
            mMethod = aMethod;
        }
        
        public ParsedCallstack Add(ParsedMethod aMethod)
        {
            ParsedCallstack call;
            if (mChildren.TryGetValue(aMethod, out call))
            {
                return call;
            }
            else
            {
                call = new ParsedCallstack(aMethod);
                mChildren[aMethod] = call;
                return call;
            }
        }

        [Browsable(false)]
        public ParsedMethod Method
        {
            get { return mMethod; }
        }

        [Browsable(false)]
        public ICollection<ParsedCallstack> Children
        {
            get { return mChildren.Values; }
        }

        [Category("Performance"), DisplayName("Number of calls")]
        public long CallCount
        {
            get { return mCallCount; }
        }

        [Category("Cycles Inclusive"), DisplayName("Total")]
        public long CycleCountInclusive
        {
            get { return mCycleCount; }
        }

        [Category("Cycles Inclusive"), DisplayName("Minimum")]
        public long MinCycleCountInclusive
        {
            get { return mMinCycleCount; }
        }

        [Category("Cycles Inclusive"), DisplayName("Maximum")]
        public long MaxCycleCountInclusive
        {
            get { return mMaxCycleCount; }
        }

        [Category("Cycles Exclusive"), DisplayName("Total")]
        public long CycleCountExclusive
        {
            get 
            {
                long cycles = mCycleCount;
                foreach (ParsedCallstack call in mChildren.Values)
                {
                    cycles -= call.CycleCountInclusive;
                }
                return cycles; 
            }
        }

        [Category("Statistics")]
        public long Transitions
        {
            get { return mTransitionCount; }
        }

        [Category("Statistics"), DisplayName("Exceptions thrown")]
        public long ExceptionsThrown
        {
            get { return mExceptionCount; }
        }

        public void AddCall()
        {
            mCallCount++;
            if (mMethod != null)
            {
                mMethod.AddCall();
            }
        }

        public void AddTransition()
        {
            mTransitionCount++;
            if (mMethod != null)
            {
                mMethod.AddTransition();
            }
        }

        public void AddException()
        {
            mExceptionCount++;
            if (mMethod != null)
            {
                mMethod.AddException();
            }
        }

        public void AddCycles(long aCycles)
        {
            mCycleCount += aCycles;
            mMinCycleCount = Math.Min(mMinCycleCount, aCycles);
            mMaxCycleCount = Math.Max(mMaxCycleCount, aCycles);
            if (mMethod != null)
            {
                mMethod.AddCycles(aCycles);
            }
        }

        public override string ToString()
        {
            return Method != null ? Method.Name : "root";
        }
    }
}
